
#include <stdlib.h>
#include <stdbool.h>

#include <misc.h>
#include <closure.h>

#include "nodelevel_aggregator.h"
// A delegating lock : do something, delegate to holder if waiting


#define BUFSIZE 64

#define DO_TASK(X) ((X).op((X).arg))

union dwordcas {
        struct {
        uint16_t guard;
        uint16_t count;
        } splitted;
        uint32_t stamp;
};



struct delegate_task {
    struct delegate_task * next;
    Closure * c;
};


struct delegate_lock {
    union dwordcas dwordcas;
    int owner;
    int fifo_guard;
    struct delegate_task * fifo_head;
    struct delegate_task * fifo_end;
};


delegate_lock_p new_delegate_lock() {
    delegate_lock_p res = new delegate_lock;
    res->owner = -1;
    return res;

}



void delegate_lock_do(  struct delegate_lock * lock, int thread_id, Closure * c )  {
    int res;
    union dwordcas localdwcas_sav= lock->dwordcas;
    union dwordcas localdwcas= localdwcas_sav;

    do {
        localdwcas_sav= lock->dwordcas;
        localdwcas= localdwcas_sav;
        localdwcas.splitted.guard += 1;
        localdwcas.splitted.count += 1;
        res = localdwcas_sav.splitted.guard;
    } while (!__sync_bool_compare_and_swap( &lock->dwordcas.stamp, localdwcas_sav.stamp, localdwcas.stamp  ));

    if ( res == 0 ) {
        lock->owner = thread_id;
    } else if ( lock->owner == thread_id ) {
        // Succeed -reentrancy
    } else {
        // Fail
        struct delegate_task * a = new delegate_task;
        a->c = c;

        while (  !__sync_bool_compare_and_swap(&lock->fifo_guard, 0, 1) ) {
            while ( lock->fifo_guard );
        }
        a->next = NULL;
        if ( lock->fifo_end != NULL ) {
            lock->fifo_end->next = a;
        } else {
            lock->fifo_head = a;
        }
        lock->fifo_end = a;
        __sync_synchronize();
        lock->fifo_guard = 0;

        // ABA aware __sync_fetch_and_sub( &lock->guard, 1 );
        union dwordcas localdwcas_sav = lock->dwordcas;
        union dwordcas localdwcas = localdwcas_sav;
        do {
                localdwcas_sav= lock->dwordcas;
                localdwcas = localdwcas_sav;

                localdwcas.splitted.guard -= 1;

        } while ( !__sync_bool_compare_and_swap( &lock->dwordcas.stamp, localdwcas_sav.stamp, localdwcas.stamp ));

        return ;
   }

    (*c)();

    // Succeed : process requests :

    while ( true ) {
         while ( lock->fifo_head == NULL)  {
        // Go out atomically, not leaving tasks behind.
                union dwordcas localdwcas = lock->dwordcas;
                union dwordcas localdwcas_new = localdwcas;
                localdwcas_new.splitted.guard = 0;
                if ( localdwcas.splitted.guard == 1 && lock->fifo_head == NULL ) {
                        lock->owner = -1;
                        if ( __sync_bool_compare_and_swap( &lock->dwordcas.stamp, localdwcas.stamp, localdwcas_new.stamp) ) {
                                 goto end;
                        }
                        lock->owner = thread_id;
                }
        }
        (*lock->fifo_head->c)();

        // Locks the fifo.
        while (  !__sync_bool_compare_and_swap(&lock->fifo_guard, 0, 1) ) {
            while ( lock->fifo_guard );
        }
        struct delegate_task * tmp = lock->fifo_head;
        lock->fifo_head = lock->fifo_head->next;

        delete tmp ;
        if ( lock->fifo_head == NULL ) {
                lock->fifo_end = NULL;
        }

        __sync_synchronize();
        // Unlocks the fifo.
        lock->fifo_guard = 0;
    }
end :
   DUMMY;

    // Ended :
}
	


